# -*- coding: utf-8 -*-
# scrap.views

import logging
import datetime
import time
import re

from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.api import memcache
from werkzeug import (
  unescape, redirect, Response,
)
from werkzeug.exceptions import (
  NotFound, MethodNotAllowed, BadRequest
)

from kay.utils import (
  render_to_response, reverse,
  get_by_key_name_or_404, get_by_id_or_404,
  to_utc, to_local_timezone, url_for, raise_on_dev
)
from kay.i18n import gettext as _
from kay.auth.decorators import login_required

from scrap.models import (
  Board, Clip
)

# Create your views here.

def timeparse(t, format):
  """Parse a time string that might contain fractions of a second.

  Fractional seconds are supported using a fragile, miserable hack.
  Given a time string like '02:03:04.234234' and a format string of
  '%H:%M:%S', time.strptime() will raise a ValueError with this
  message: 'unconverted data remains: .234234'.  If %S is in the
  format string and the ValueError matches as above, a datetime
  object will be created from the part that matches and the
  microseconds in the time string.
  """
  try:
    return datetime.datetime(*time.strptime(t, format)[0:6]).time()
  except ValueError, msg:
    if "%S" in format:
      msg = str(msg)
      mat = re.match(r"unconverted data remains:"
                     " \.([0-9]{1,6})$", msg)
      if mat is not None:
        # fractional seconds are present - this is the style
        # used by datetime's isoformat() method
        frac = "." + mat.group(1)
        t = t[:-len(frac)]
        t = datetime.datetime(*time.strptime(t, format)[0:6])
        microsecond = int(float(frac)*1e6)
        return t.replace(microsecond=microsecond)
      else:
        mat = re.match(r"unconverted data remains:"
                       " \,([0-9]{3,3})$", msg)
        if mat is not None:
          # fractional seconds are present - this is the style
          # used by the logging module
          frac = "." + mat.group(1)
          t = t[:-len(frac)]
          t = datetime.datetime(*time.strptime(t, format)[0:6])
          microsecond = int(float(frac)*1e6)
          return t.replace(microsecond=microsecond)

    raise

def delete_clip(key):
  from google.appengine.ext import db
  clip = db.get(key)
  if clip:
    clip.delete()

def get_clips(request):
  import simplejson
  if request.method == "POST":
    data_string= request.form.get("data")
    data = simplejson.loads(data_string)
    board = data['board']
    ret = []
    if board:
      b = Board.get_or_insert(key_name=board)
      q = Clip.all().ancestor(b).order("clip_number")
      if data['clip_number']:
        q = q.filter("clip_number >", int(data['clip_number']))
      clips = q.fetch(50)
      for clip in clips:
        ret.append(
          {"name": clip.poster_name,
           "content": clip.content,
           "url": clip.url,
           "clip_number": clip.clip_number})
    json_data = simplejson.dumps(ret)
    return Response(json_data, content_type="application/json")

def get_root_url(url):
  import re
  try:
    p = re.compile(r"https?://[^/]+")
    m = p.match(url)
    return m.group()
  except Exception:
    return url

def get_base_name(url):
  try:
    slash = url.rindex('/')
    return url[:slash+1]
  except Exception:
    return url

def convert_to_absolute_path(attr, val, url):
  if attr == "src" and not val.startswith("http"):
    if val.startswith("/"):
      return attr, get_root_url(url)+val
    else:
      return attr, get_base_name(url)+val
  else:
    return attr, val  

def post_clip(request):
  import simplejson

  from google.appengine.ext import deferred
  from BeautifulSoup import BeautifulSoup, Comment
  from kay.conf import settings

  import sanitizer

  if request.method == "POST":
    data_string= request.form.get("data")
    logging.debug(data_string)
    data = simplejson.loads(data_string)
    name = data['name']
    board = data['board']
    clip_content = data['clip']
    clip_url = data['url']
    html_sanitizer = sanitizer.get_default_sanitizer()
    sanitized = html_sanitizer.sanitize(clip_content)
    # TODO its better to use BeautifulSoup only once
    soup = BeautifulSoup(sanitized)
    for tag in soup.findAll(True):
      tag.attrs = [convert_to_absolute_path(attr, val, clip_url)
                   for attr, val in tag.attrs]
    content = soup.renderContents().decode('utf8')

    def txn():
      b = Board.get_by_key_name(board)
      if b is None:
        b = Board(key_name=board, clip_number=1)
        b.put()
      else:
        b.clip_number = b.clip_number + 1
        b.put()
      clip = Clip(poster_name=name, content=content, url=clip_url,
                  parent=b, clip_number=b.clip_number)
      clip.put()
      logging.debug("clip saved")
      return clip
    clip = db.run_in_transaction(txn)
    expiration_date = datetime.datetime.now() + \
        datetime.timedelta(seconds=settings.CLIP_EXPIRATION_SECONDS)
    deferred.defer(delete_clip, clip.key(), _eta=expiration_date)
    return Response(simplejson.dumps({"result": True}))
  return Response(simplejson.dumps({"result": False}))

def index(request):
  return render_to_response('scrap/index.html', {})
